package jmetal.metaheuristics.moead;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.logging.FileHandler;
import java.util.logging.Logger;

import jmetal.core.Algorithm;
import jmetal.core.Operator;
import jmetal.core.Problem;
import jmetal.core.SolutionSet;
import jmetal.operators.crossover.CrossoverFactory;
import jmetal.operators.mutation.MutationFactory;
import jmetal.operators.selection.SelectionFactory;
import jmetal.qualityIndicator.QualityIndicator;
import jmetal.util.HvIndicator;
import jmetal.util.JMException;
import jmetal.util.MathUtil;

/**
 * Class to configure and execute the NSGA-II algorithm.
 * 
 * Besides the classic NSGA-II, a steady-state version (ssNSGAII) is also
 * included (See: J.J. Durillo, A.J. Nebro, F. Luna and E. Alba "On the Effect
 * of the Steady-State Selection Scheme in Multi-Objective Genetic Algorithms"
 * 5th International Conference, EMO 2009, pp: 183-197. April 2009)
 */

public class MOEAD_DTLZ_exp {
	public static Logger logger_; // Logger object
	public static FileHandler fileHandler_; // FileHandler object

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void main(String[] args)
			throws JMException, SecurityException, IOException, ClassNotFoundException, NoSuchMethodException,
			InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Problem problem; // The problem to solve
		Algorithm algorithm; // The algorithm to use
		Operator crossover; // Crossover operator
		Operator mutation; // Mutation operator

		HashMap parameters; // Operator parameters

		QualityIndicator indicators; // Object to get quality indicators

		indicators = null;
		String pfDirect;
		String outDirect = "";

		String[] probName = { "jmetal.problems.DTLZ.DTLZ1", "jmetal.problems.DTLZ.DTLZ2", "jmetal.problems.DTLZ.DTLZ3",
				"jmetal.problems.DTLZ.DTLZ4"};

		Integer[] popuSize = { 0, 0, 0, 120, 0, 210, 0, 0, 156, 0, 275 };// 种群数量
		Integer[] varSize = { 4, 9, 9, 9, 9, 9, 19 };  
		Integer[] dimension = { 3, 5, 8,10 };//目标数
		for (int dimNum = 0; dimNum < dimension.length; dimNum++) {
			for (int probNum = 0; probNum < probName.length; probNum++) {
				Class<?> dtlz = Class.forName(probName[probNum]);
				Constructor<?> constr = dtlz.getConstructor(String.class, Integer.class, Integer.class);
				problem = (Problem) constr.newInstance("Real",dimension[dimNum]+varSize[probNum],dimension[dimNum]);
				pfDirect = "new_pf/" + problem.getName() + "_M" + problem.getNumberOfObjectives() + ".dat";
				indicators = new QualityIndicator(problem, pfDirect);
				
				/**
				 * 1、修改文件名 2、选择算子
				 */
				outDirect = "results/MOEAD/" + problem.getName() + "/"+dimension[dimNum]+"D_";

				algorithm = initializeAlg(problem, popuSize);
				
				int run = 20;
				String path = outDirect+"IGD"+".dat";
				FileOutputStream output = new FileOutputStream(new File(path));
				double[] igds = new double[run];
				for (int i = 0; i < run; i++) {
					System.out.println(problem.getName()+"_"+problem.getNumberOfObjectives()+"D_RUN_"+i);
					// Execute the Algorithm
					long initTime = System.currentTimeMillis();
					SolutionSet population = algorithm.execute();
					long estimatedTime = System.currentTimeMillis() - initTime;

					// Result messages
					System.out.println("Total execution time: " + estimatedTime + "ms");
					System.out.println("Write to "+outDirect + "FUN" + i);
					population.printObjectivesToFile(outDirect + "FUN" + i);
					igds[i] = indicators.getIGD(population);
					String indic = "Run "+i+":\t"+igds[i]+"\n";
					System.out.println(indic);
					output.write(indic.getBytes());
				}
				DecimalFormat aveF= new DecimalFormat("0.0000E00");
				DecimalFormat stdF = new DecimalFormat("0.00E00");
				output.write(("ave"+": \t"+aveF.format(MathUtil.getAvarage(igds))+"\n").getBytes());
				output.write(("std"+": \t"+stdF.format(MathUtil.getStd(igds))+"\n").getBytes());
				output.close();
			}
		}
	} // main

	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static Algorithm initializeAlg(Problem problem, Integer[] popuSize) throws JMException {
		Algorithm algorithm;
		Operator crossover;
		Operator mutation;
		HashMap parameters;
		algorithm = new MOEAD(problem);

		// Algorithm parameters
		algorithm.setInputParameter("dataDirectory",
			    "");
		algorithm.setInputParameter("populationSize", popuSize[problem.getNumberOfObjectives()]);
		algorithm.setInputParameter("maxEvaluations", popuSize[problem.getNumberOfObjectives()] * 1001);

		algorithm.setInputParameter("T", 20) ;
		algorithm.setInputParameter("delta", 0.9) ;
		algorithm.setInputParameter("nr", 2) ;
		
		// Crossover operator 
		parameters = new HashMap() ;
	    parameters.put("probability", 1.0) ;
	    parameters.put("distributionIndex", 30.0) ;
	    crossover = CrossoverFactory.getCrossoverOperator("SBXCrossover", parameters);     
		// Mutation operator
		parameters = new HashMap() ;
		parameters.put("probability", 1.0/problem.getNumberOfVariables()) ;
		parameters.put("distributionIndex", 20.0) ;
		mutation = MutationFactory.getMutationOperator("PolynomialMutation", parameters);                    
		
		algorithm.addOperator("crossover",crossover);
		algorithm.addOperator("mutation",mutation);
		return algorithm;
	}
}
